﻿namespace OverStore.Runtime.ObjectRepository.ChangesTracker
{
    /// <summary>
    /// Support storing initial state of object and
    /// get the difference and current object changes
    /// </summary>
    /// <typeparam name="TInstance">The type of the instance.</typeparam>
    public interface IChangesTracker<TInstance> : IRuntimeComponent
        where TInstance : class
    {
        /// <summary>
        /// <para> Aquires the instance that does not exists in data storage.</para>
        /// <para> If instance is not registered in changes tracker, it gets <see cref="InstanceState.Added"/> state.
        /// Otherwise, instance state still unchanged.</para>
        /// </summary>
        /// <param name="instance">The instance to aquire.</param>
        /// <exception cref="PersistingRuntimeException">Error occured during changes tracker operation.</exception>
        void CaptureNewInstance(TInstance instance);

        /// <summary>
        /// <para> Notify changes tracker that object should be deleted on save.</para>
        /// <para> If instance does not registered in the changes tracker previously or has <see cref="InstanceState.Added"/> state, 
        /// it get <see cref="InstanceState.AddedThenDeleted"/> state. Otherwise, instance gets <see cref="InstanceState.MarkedAsDeleted"/> state. </para>
        /// </summary>
        /// <param name="instance">Object to be marked as deleted.</param>
        /// <exception cref="PersistingRuntimeException">Error occured during method executing.</exception>
        void MarkAsDeleted(TInstance instance);

        /// <summary>
        /// Marks instance as dirty. Changes Tracker reports instance data are changed on dirty instances, 
        /// even if data actually are not changed.
        /// </summary>
        /// <param name="instance">Object to mark as dirty.</param>
        /// <exception cref="PersistingRuntimeException">Error occured during method execution.</exception>
        void MarkAsDirty(TInstance instance);

        /// <summary>
        ///     <para> Accepts data changes made to specified instance and aquire current state of instance's data
        /// as new original instance data.</para>
        ///     <para> If instance state was <see cref="InstanceState.MarkedAsDeleted"/> or <see cref="InstanceState.AddedThenDeleted"/>,
        /// instance state become <see cref="InstanceState.Added"/>, otherwise state become <see cref="InstanceState.Existing"/>.</para>
        /// </summary>
        /// <param name="instance">The instance to accept changes of it.</param>
        /// <exception cref="PersistingRuntimeException">Error occured during method executing.</exception>
        void AcceptChanges(TInstance instance);

        /// <summary>
        /// Return <see cref="InstanceState"/> of specified object.
        /// </summary>
        /// <param name="instance">Instance to get state for.</param>
        /// <returns>
        /// The <see cref="InstanceState"/> of specified instance.
        /// </returns>
        /// <exception cref="PersistingRuntimeException">Error occured during method executing.</exception>
        InstanceState GetInstanceState(TInstance instance);

        /// <summary>
        ///     <para> Determines whether the data of specified instance were modified.</para>
        ///     <para> If specified instance was not previously registered in the changes tracker,
        /// method returns <c>true</c>.</para>
        /// <para>If object was marked as dirty previosly, the method returns <c>true</c>.</para>
        /// </summary>
        /// <param name="instance">The instance to determine data modification.</param>
        /// <returns>
        ///     <c>true</c> if data of the specified instance was modifier; otherwise, <c>false</c>.
        /// </returns>
        /// <exception cref="PersistingRuntimeException">Error occured during changes tracker operation.</exception>
        bool IsInstanceDataChanged(TInstance instance);

        /// <summary>
        /// Update instance state and data changes state of specified instance corresponding to specified parameters.
        /// </summary>
        /// <param name="actualInstance">Actual instance registered in session which changes should be handled.</param>
        /// <param name="objectExistsInStorage"><c>true</c> if object exists in data storage; otherwise <c>false</c>.</param>
        /// <param name="instanceDataAreChanged"><c>true</c> if instance data are changed compare to data from storage.</param>
        /// <exception cref="PersistingRuntimeException">Error occured during attaching object.</exception>
        /// <exception cref="T:OverStore.Exceptions.PersistenceOperationIsNotSupportedException">Operation is not supported because of configuration part responsible for this operation is missing or does not support specific functionallity.</exception>
        void Attach(TInstance actualInstance, bool objectExistsInStorage, bool instanceDataAreChanged);
    }
}